package com.baiyue.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baiyue.entity.Menu;
import com.baiyue.entity.UserEntity;
import com.baiyue.exception.GlobalException;
import com.baiyue.manager.MenuManager;
import com.baiyue.mapper.MenuMapper;
import com.baiyue.mapper.UserMapper;
import com.baiyue.model.menu.MenuDataRequest;
import com.baiyue.model.menu.MenuTreeDataResponse;
import com.baiyue.model.menu.TreeNodeResponse;
import com.baiyue.result.CodeMsg;
import com.baiyue.service.MenuService;
import com.baiyue.utils.BeanMapperUtil;
import com.baiyue.utils.SplitUtil;
import com.baiyue.utils.UserHolderUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 伍波
 * @date 2023-04-17
 */
@Service
public class MenuServiceImpl implements MenuService {
    private static final Logger logger = LoggerFactory.getLogger(MenuServiceImpl.class);

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private MenuManager menuManager;
    /**
     * 新增菜单
     *
     * @param request
     */
    @Transactional(rollbackFor = Exception.class) // 添加事务
    @Override
    public void insertMenu(MenuDataRequest request) {
        logger.info("新增菜单入参:{}", JSONObject.toJSONString(request));
        Menu menu;
        if (request.getParentId() == 0 && StringUtils.isEmpty(request.getPath())) {
            request.setPath("/home");
        }
        if (request.getParentId() != 0) {
            menu = menuMapper.getMenuById(request.getParentId());
            if (Objects.isNull(menu)) {
                logger.warn("一级菜单ID不存在");
                throw new GlobalException(CodeMsg.MENU_NOT_EXIST);
            }
            logger.info("新增二级菜单，查询一级菜单出参:{}", JSONObject.toJSONString(menu));
        }
        Menu insertMenu = BeanMapperUtil.map(request, Menu.class);
        insertMenu.setCreateTime(new Date());
        insertMenu.setUpdateTime(new Date());
        String user = UserHolderUtil.getUser().getUsername();
        insertMenu.setCreateName(user);
        insertMenu.setUpdateName(user);
        Integer result = menuMapper.insert(insertMenu);
        if (result <= 0) {
            throw new GlobalException(CodeMsg.FAILURE);
        }
    }

    /**
     * 构建菜单树
     *
     * @param allowedIds         允许访问的菜单 ID 列表
     * @param parentId           父节点 ID
     * @param firstLevelMenuName 一级菜单名称
     * @return 菜单树根节点
     */
    private List<MenuTreeDataResponse> buildTree(List<Integer> allowedIds, Integer parentId, String firstLevelMenuName) {
        // 如果是查询一级菜单，则先查询一级菜单对应的子菜单
        if (parentId == 0 && StringUtils.isNotBlank(firstLevelMenuName)) {
            List<Menu> firstLevelMenus = menuMapper.findByNameLike(firstLevelMenuName);
            if (firstLevelMenus != null && !firstLevelMenus.isEmpty()) {
                List<Integer> finalAllowedIds = allowedIds;
                allowedIds = firstLevelMenus.stream()
                        .map(Menu::getId)
                        .filter(finalAllowedIds::contains)
                        .collect(Collectors.toList());
                parentId = firstLevelMenus.get(0).getId();
            }
        }

        // 查询父菜单对应的子菜单，并过滤出允许访问的菜单
        List<Integer> finalAllowedIds1 = allowedIds;
        List<Menu> subMenus = menuMapper.findByParentId(parentId).stream()
                .filter(menu -> finalAllowedIds1.contains(menu.getId()))
                .collect(Collectors.toList());

        // 存储菜单树结果
        List<MenuTreeDataResponse> result = new ArrayList<>();

        // 迭代构建菜单树
        for (Menu menu : subMenus) {
            // 封装MenuTreeDataResponse
            MenuTreeDataResponse data = new MenuTreeDataResponse(menu);
            // 递归调用,设置子菜单
            data.setChildren(buildTree(allowedIds, menu.getId(), null));
            // 添加到结果中
            result.add(data);
        }
        return result;
    }

    /**
     * 构建菜单树
     *
     * @param parentId 父节点 ID
     * @return 菜单树根节点
     */
    private List<MenuTreeDataResponse> buildTree(Integer parentId) {
        // 查询父菜单对应的子菜单
        List<Menu> subMenus = menuMapper.findByParentId(parentId);

        // 存储菜单树结果
        List<MenuTreeDataResponse> result = new ArrayList<>();

        // 迭代构建菜单树
        for (Menu menu : subMenus) {
            // 封装MenuTreeDataResponse
            MenuTreeDataResponse data = new MenuTreeDataResponse(menu);
            // 递归调用,设置子菜单
            data.setChildren(buildTree(menu.getId()));
            // 添加到结果中
            result.add(data);
        }
        return result;
    }

    /**
     * 获取菜单树数据
     *
     * @return 菜单树
     */
    @Override
    public List<MenuTreeDataResponse> getMenuTreeByUser(MenuDataRequest request) {
        Integer parentId = request.getParentId();
        String firstLevelMenuName = request.getName();
        final int defaultParentId = 0;
        UserEntity user = UserHolderUtil.getUser();
        // 查询用户有权访问的菜单 ID 列表
        String allowedMenuIds = userMapper.findAllowedMenuIds(user.getId());
        //当用户权限为管理员并且没有分配菜单时，默认返回全部菜单
        if (user.getNickname() == 0 && StringUtils.isEmpty(allowedMenuIds)) {
            return getMenuTreeByAll(request);
        }
        List<Integer> allowedIds = new ArrayList<>();
        // 构建菜单树时，只使用用户有权访问的菜单 ID
        if (!StringUtils.isEmpty(allowedMenuIds)) {
            String menuIds = menuManager.menuIds(allowedMenuIds);
            allowedIds = SplitUtil.InterSplit(menuIds);
        }
        // 如果菜单树为空，则返回空列表
        return buildTree(allowedIds, parentId != null ? parentId : defaultParentId,
                StringUtils.isNotBlank(firstLevelMenuName) ? firstLevelMenuName.trim() : null);
    }

    /**
     * 获取所有菜单树
     *
     * @param request
     * @return
     */
    @Override
    public List<MenuTreeDataResponse> getMenuTreeByAll(MenuDataRequest request) {
        Integer parentId = request.getParentId();
        String firstLevelMenuName = request.getName();

        final int defaultParentId = 0;

        // 查询一级菜单并构建一级菜单树
        Optional<List<MenuTreeDataResponse>> firstLevelTreeDataList = Optional.ofNullable(
                parentId == null && StringUtils.isNotBlank(firstLevelMenuName) ? menuMapper.findByNameLike(firstLevelMenuName)
                        .stream().map(menu -> {
                            List<MenuTreeDataResponse> children = buildTree(menu.getId());
                            MenuTreeDataResponse response = new MenuTreeDataResponse(menu);
                            response.setChildren(children);
                            return response;
                        }).collect(Collectors.toList())
                        : null);

        // 优先使用传入的 parentId 查询,如果为空则使用默认值 DEFAULT_PARENT_ID
        return firstLevelTreeDataList.orElseGet(() -> buildTree(parentId != null ? parentId : defaultParentId));
    }

    /**
     * 获取菜单树列表用于新增用户
     * @param request
     * @return
     */
    @Override
    public List<TreeNodeResponse> getAllMenuList(MenuDataRequest request) {
        return Optional.ofNullable(getMenuTreeByAll(request))
                .map(JSON::toJSONString)
                .map(JSONArray::parseArray)
                .map(menuManager::getMenuList)
                .orElseGet(() -> {
                    logger.warn("获取菜单列表为空");
                    return Collections.emptyList();
                });
    }
}
